// Copyright (c) Microsoft Corporation. All rights reserved.

namespace SPPivotViewer.HttpHandler.Internal
{
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Collections.Generic;
    using System.Drawing.Drawing2D;
    using SPPivotViewer.Utility;
    using Microsoft.SharePoint;


    /// <summary>
    /// The base class for item image implementations that create the image bytes from some source.
    /// Just override the MakeImage() method.
    /// </summary>
    internal abstract class ImageBase : ImageProviderBase
    {
        // Constructors, Finalizer and Dispose
        //======================================================================

        public ImageBase()
        {
        }


        // Interface realizations and base class overrides
        //======================================================================

        #region ImageProviderBase Members

        public override System.Drawing.Size Size
        {
            get
            {
                EnsureIsSize();
                return m_size;
            }

            protected set
            {
                m_size = value;
            }
        }

        public override byte[][] ImageData
        {
            get
            {
                EnsureIsLoaded();
                return m_imageData;
            }
        }

        protected byte[][] ImageDataInternal
        {
            get { return m_imageData; }
        }

        public override void Draw(Graphics g, Rectangle itemRectangle, int level)
        {
            EnsureIsLoaded();

            using (MemoryStream stream = this.CreateImageStream(this.ImageData, level))
            using (Image image = Image.FromStream(stream))
            {
                System.Drawing.Size scaledSize = ScaleToFillSize(image.Size, itemRectangle.Size);
                g.DrawImage(image, itemRectangle.X, itemRectangle.Y, scaledSize.Width, scaledSize.Height);
            }
        }

        #endregion


        // Protected Methods
        //======================================================================

        /// <summary>
        /// If the image is a constant size, you may override this to set the size directly.
        /// </summary>
        protected virtual void EnsureIsSize()
        {
            EnsureIsLoaded();
        }

        protected virtual void EnsureIsLoaded()
        {
            //Note, this method can be called concurrently by multiple image-request threads.
            // TODO: For non-sample use, lock the portion of code that loads the image to avoid
            // duplicating work, or implement a shared queue that manages asynchronous loading of all source images.

            if (null == m_imageData)
            {
                try
                {
                    Image[] image = MakeImage();
                    List<byte[]> lstByte = new List<byte[]>();
                    foreach (Image img in image)
                    {
                        m_size = img.Size;
                        using (MemoryStream stream = new MemoryStream())
                        {
                            img.Save(stream, ImageFormat.Jpeg);
                            lstByte.Add(stream.ToArray());
                        }
                        img.Dispose();

                    }
                    m_imageData = lstByte.ToArray();
                }
                catch { }
            }
        }

        protected Image MakeLayer2(Image img, string title, Dictionary<string, string> MetaData)
        {
            using (Bitmap bmp = new Bitmap(1024, 768))
            {

                Rectangle rect = new Rectangle(0, 0, bmp.Width - 500, bmp.Height - 100);
                float nPercent = 0;
                float nPercentH = 0;
                float nPercentW = 0;

                nPercentW = (((float)(rect.Width * 0.8) / (float)img.Width));
                nPercentH = (((float)(rect.Height * 0.8) / (float)img.Height));

                if (nPercentH < nPercentW)
                    nPercent = nPercentH;
                else
                    nPercent = nPercentW;

                int destWidth = (int)(img.Width * nPercent);
                int destHeight = (int)(img.Height * nPercent);

                using (Graphics g = Graphics.FromImage(bmp))
                {
                    Rectangle rectImage = new Rectangle(0, 0, bmp.Width, bmp.Height);
                    SolidBrush lgb = new SolidBrush(Color.FromArgb(229, 57, 33));
                    g.FillRectangle(lgb, rectImage);
                    Rectangle rectShadow = new Rectangle((rect.Width - destWidth) / 2 + 500, (rect.Height - destHeight) / 2 + 50, destWidth, destHeight);
                    DropShadow(ref img, Color.Black, Color.FromArgb(229, 57, 33));
                    g.DrawImage(img, rectShadow);
                    Font drawFont = new Font("Segoe UI", 30, FontStyle.Bold | FontStyle.Underline);
                    SolidBrush drawBrush = new SolidBrush(Color.White);
                    PointF drawPoint = new PointF(50.0F, 50.0F);
                    g.DrawString(title, drawFont, drawBrush, drawPoint);
                    DrawMetaData(g, MetaData);


                    drawBrush.Dispose();
                    drawBrush = null;
                    lgb.Dispose();
                    lgb = null;
                    drawFont.Dispose();
                    drawFont = null;
                }

                MemoryStream ms = new MemoryStream();
                bmp.Save(ms, ImageFormat.Jpeg);
                return Image.FromStream(ms);

            }
        }

        private void DrawMetaData(Graphics g, Dictionary<string, string> MetaData)
        {
            if (MetaData == null)
                return;
            Font drawFontKey = new Font("Segoe UI", 20, FontStyle.Bold | FontStyle.Underline);
            Font drawFontValue = new Font("Segoe UI", 20);
            SolidBrush drawBrush = new SolidBrush(Color.White);
            int yStart = 110;
            try
            {

                foreach (string key in MetaData.Keys)
                {
                    int xStart = 50;
                    if (yStart > 710)
                        break;
                    g.DrawString(key, drawFontKey, drawBrush, new PointF(xStart, yStart));
                    SizeF sizeValue = g.MeasureString(MetaData[key], drawFontValue);
                    SizeF sizeKey = g.MeasureString(key, drawFontValue);
                    if (sizeValue.Width > 500)
                        yStart += (int)sizeKey.Height + 1;
                    else
                    {
                        xStart += (int)sizeKey.Width + 10;
                    }

                    g.DrawString(MetaData[key], drawFontValue, drawBrush, new PointF(xStart, yStart));
                    yStart += (int)g.MeasureString(key, drawFontValue).Height * 2 + 1;
                }
            }
            finally
            {
                drawFontKey.Dispose();
                drawFontValue.Dispose();
                drawBrush.Dispose();
                drawFontKey = null;
                drawFontValue = null;
                drawBrush = null;
            }
        }

        protected Image MakeLayer1(Image img, string title)
        {
            using (Bitmap bmp = new Bitmap(1024, 768))
            {

                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height - 100);
                float nPercent = 0;
                float nPercentH = 0;
                float nPercentW = 0;

                nPercentW = (((float)(rect.Width * 0.8) / (float)img.Width));
                nPercentH = (((float)(rect.Height * 0.8) / (float)img.Height));

                if (nPercentH < nPercentW)
                    nPercent = nPercentH;
                else
                    nPercent = nPercentW;

                int destWidth = (int)(img.Width * nPercent);
                int destHeight = (int)(img.Height * nPercent);

                using (Graphics g = Graphics.FromImage(bmp))
                {
                    Rectangle rectImage = new Rectangle(0, 0, bmp.Width, bmp.Height);
                    SolidBrush brush = new SolidBrush(Color.FromArgb(242, 149, 28));
                    g.FillRectangle(brush, rectImage);
                    brush.Dispose();
                    brush = null;
                    brush = new SolidBrush(Color.White);
                    Rectangle rectShadow = new Rectangle((rect.Width - destWidth) / 2, (rect.Height - destHeight) / 2 + 50, destWidth, destHeight);
                    g.FillRectangle(brush, rectShadow);
                    g.DrawImage(img, rectShadow);
                    brush.Dispose();
                    brush = null;
                    //DropShadow(ref bmpShadow, Color.Black, Color.FromArgb(242, 149, 28));
                    Font drawFont = new Font("Segoe UI", 36, FontStyle.Bold);
                    SolidBrush drawBrush = new SolidBrush(Color.Black);
                    PointF drawPoint = new PointF(50.0F, 50.0F);
                    g.DrawString(title, drawFont, drawBrush, drawPoint);
                    drawBrush.Dispose();
                    drawFont.Dispose();
                    drawBrush = null;
                    drawFont = null;
                }
                MemoryStream ms = new MemoryStream();
                bmp.Save(ms, ImageFormat.Jpeg);

                return Image.FromStream(ms);
            }
        }

        protected Image MakeLayer0(Image img)
        {
            using (Bitmap bmp = new Bitmap(1024, 768))
            {

                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                float nPercent = 0;
                float nPercentH = 0;
                float nPercentW = 0;

                nPercentW = (((float)(rect.Width * 0.8) / (float)img.Width));
                nPercentH = (((float)(rect.Height * 0.8) / (float)img.Height));

                if (nPercentH < nPercentW)
                    nPercent = nPercentH;
                else
                    nPercent = nPercentW;

                int destWidth = (int)(img.Width * nPercent);
                int destHeight = (int)(img.Height * nPercent);

                using (Graphics g = Graphics.FromImage(bmp))
                {
                    SolidBrush brush = new SolidBrush(Color.FromArgb(153, 153, 153));
                    g.FillRectangle(brush, rect);
                    brush.Dispose();
                    brush = null;
                    brush = new SolidBrush(Color.White);
                    Rectangle rectShadow = new Rectangle((rect.Width - destWidth) / 2, (rect.Height - destHeight) / 2, destWidth, destHeight);
                    g.FillRectangle(brush, rectShadow);
                    g.DrawImage(img, rectShadow);
                    brush.Dispose();
                    brush = null;
                }

                MemoryStream ms = new MemoryStream();
                bmp.Save(ms, ImageFormat.Jpeg);

                return Image.FromStream(ms);
            }

        }

        protected void FillLayers(Image img, string title, Dictionary<string, string> metadata, ref List<Image> layers)
        {
            if (layers == null)
                return;
            layers.Add(MakeLayer0(img));
            bool _b3Layers = false;
            if (bool.TryParse(PV4SPSettings.GetValue(SPContext.Current.Web, PV4SPSettings.cst3Layers), out _b3Layers) && _b3Layers)
            {
                layers.Add(MakeLayer1(img, title));
                layers.Add(MakeLayer2(img, title, metadata));
            }
        }


        /// <summary>
        /// Override this method to return the desired Image object to display.
        /// </summary>
        protected abstract Image[] MakeImage();


        // Private Methods
        //======================================================================

        internal static System.Drawing.Size ScaleToFillSize(System.Drawing.Size size, System.Drawing.Size maxSize)
        {
            System.Drawing.Size newSize = new System.Drawing.Size();
            double aspectRatio = ((double)size.Width) / size.Height;
            if (aspectRatio > 1.0)
            {
                newSize.Width = maxSize.Width;
                newSize.Height = (int)((double)newSize.Width / aspectRatio);
            }
            else
            {
                newSize.Height = maxSize.Height;
                newSize.Width = (int)(newSize.Height * aspectRatio);
            }
            return newSize;
        }


        // Private Fields
        //======================================================================
        public void DropShadow(ref Image SourceImage, Color ShadowColor, Color BackgroundColor)
        {
            int _shadowOpacity = 190;
            int _shadowSoftness = 2;
            int _shadowDistance = SourceImage.Width/10+1;
            Graphics g = null;
            bool _shadowRoundedEdges = true;
            Bitmap ImgShadow = null;
            Bitmap ImgTarget = null;
            if (ShadowColor == Color.Transparent)
                ShadowColor = Color.Black;


            if (BackgroundColor == Color.Transparent)
                BackgroundColor = Color.White;



            int shWidth = (int)(SourceImage.Width / _shadowSoftness);
            int shHeight = (int)(SourceImage.Height / _shadowSoftness);
            ImgShadow = new Bitmap(shWidth, shHeight);

            g = Graphics.FromImage(ImgShadow);
            g.Clear(Color.Transparent);
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.SmoothingMode = SmoothingMode.AntiAlias;

            int sre = 0;

            if (_shadowRoundedEdges == true)
                sre = 1;

            g.FillRectangle(new SolidBrush(Color.FromArgb(_shadowOpacity, ShadowColor)), sre, sre, shWidth, shHeight);

            g.Dispose();
            g = null;

            int d_shWidth = SourceImage.Width + _shadowDistance;

            int d_shHeight = SourceImage.Height + _shadowDistance;

            ImgTarget = new Bitmap(d_shWidth, d_shHeight);

            g = Graphics.FromImage(ImgTarget);

            g.Clear(BackgroundColor);

            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.SmoothingMode = SmoothingMode.AntiAlias;

            g.DrawImage(ImgShadow, new Rectangle(0, 0, d_shWidth, d_shHeight), 0, 0, ImgShadow.Width, ImgShadow.Height, GraphicsUnit.Pixel);
            SolidBrush sb=new SolidBrush(Color.White);
            g.FillRectangle(sb, new Rectangle(0, 0, SourceImage.Width, SourceImage.Height));
            sb.Dispose();
            g.DrawImage(SourceImage, new Rectangle(0, 0, SourceImage.Width, SourceImage.Height), 0, 0, SourceImage.Width, SourceImage.Height, GraphicsUnit.Pixel);



            g.Dispose();

            g = null;

            ImgShadow.Dispose();

            ImgShadow = null;

            SourceImage = new Bitmap(ImgTarget);

            ImgTarget.Dispose();

            ImgTarget = null;

        }


        System.Drawing.Size m_size;
        byte[][] m_imageData;
    }
    public enum ShadowDirections
    {

        TOP_RIGHT = 1,

        BOTTOM_RIGHT = 2,

        BOTTOM_LEFT = 3,

        TOP_LEFT = 4

    }


}
